﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using Common.Communication;
using Common.DataBaseNew;

namespace WCFService
{
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
    class ServerCommu : IServerCommunication
    {

        private static Dictionary<User, IClientCommunication> users = new Dictionary<User, IClientCommunication>();
        private LogicForumImp logicforumimp = new LogicForumImp();
        private static int guest_No = 1;
        public IClientCommunication CurrentCallback
        {
            get
            {
                return OperationContext.Current.GetCallbackChannel<IClientCommunication>();
            }
        }
        public ServiceHost host = null;

        public void InitServer()
        {
            using (ServiceHost host = new ServiceHost(
                typeof(ServerCommu),
                new Uri("net.tcp://localhost:8000")))
            {
                host.AddServiceEndpoint(typeof(IServerCommunication),
                  new NetTcpBinding(),
                  "ISubscribe");

                try
                {
                    host.Open(new TimeSpan(1000));
                    //host.Abort();
                    if (logicforumimp == null)
                        logicforumimp = new LogicForumImp();
                    Console.WriteLine("Successfully opened port 8000.");
                    Console.ReadLine();
                    host.Close();
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.Message);
                }
            }
        }


        public void Login(string flag, string username, Byte[] password, int forumid)
        {//if flag == guest its guest
            //if flag ==login its regular login

            System.Text.UTF8Encoding UTFEncoder = new System.Text.UTF8Encoding();



            if (flag.Equals("guest"))
            {//if its guest
                Boolean flagres = logicforumimp.login(forumid, "guest" + guest_No, "");
                User user = new User("guest" + guest_No, "", "", 0, "");
                CurrentCallback.ReceiveJoin(user, true, "succed guest login");
                guest_No++;
                IClientCommunication ic=this.CurrentCallback;
                users.Add(user, ic);

                ic.ReceiveNotify("Logged in as a Guest");     
                    
            }
            else
            {
                IClientCommunication ic = this.CurrentCallback;
                Boolean flagres = logicforumimp.login(forumid, username, UTFEncoder.GetString(password));
                if (flagres == true)
                {
                    User res = logicforumimp.getuser(forumid, username);
                    //IClientCommunication callback = this.GetUserCallBack(res());
                    CurrentCallback.ReceiveJoin(res, true, "succed login");

                    users.Add(res, ic);
                    ic.ReceiveNotify("Logged in as a " + username);  
                }
                else
                    ic.RecieveError("Wrong User name or Password");
            }
        }

        public void Logout(Common.DataBaseNew.User me,int forumid)
        {
            //Boolean flag    =   logicforumimp.logout(me, forumid);
            //change Ilya
            if (String.Compare(me.getUserName(), "admin", false) != 0)
            {
                logicforumimp.logout(me, forumid);
            }
            users.Remove(me);
            
        }

        public void Register(string name, string last, string nick, string pass, string email,int forumid)
        {
            int password = int.Parse(pass);
            Boolean flag = logicforumimp.Register(forumid, nick, name, last, password, email);
            if (flag == true)
            {//need to do login
                User user=logicforumimp.getuser(forumid, nick);
                System.Text.UTF8Encoding UTFEncoder = new System.Text.UTF8Encoding();
                Byte[] encr = UTFEncoder.GetBytes(pass);
                this.Login("login", nick, encr, forumid);
                this.notifyForum(forumid,"Welcome our New member " + nick);
             }
        }

        public void GetForum(Common.ClientRequest req)
        {
            Forum forum = logicforumimp.getForum(req.getUser(), req.getForumId());
            IClientCommunication callback = this.GetUserCallBack(req.getUser());
            if (forum != null)
            {
                callback.ReceiveForum(forum);
            }

        }

        public void AddForum(Common.DataBaseNew.User me, string forummanagername, string forum)
        {
            Boolean flag = logicforumimp.AddForum(me, forum,forummanagername);
        }

        //dont need
        public void EditForum(Common.ClientRequest req)
        {
           
        }

        //dont need
        public void DeleteForum(Common.ClientRequest req)
        {
         
        }

        public void GetSubForum(Common.ClientRequest req)
        {
            SubForum sb= this.logicforumimp.getSubForum(req.getUser(), req.getForumId(), req.getSubForumId());
            IClientCommunication callback = this.GetUserCallBack(req.getUser());
            if (sb != null)
                callback.ReceiveSubForum(sb);
            else
            {
                //if dont have the permission to do it
               // callback.AutherizationError();
            }

        }

        public void AddSubForum(Common.ClientRequest req)
        {
          Boolean flag=this.logicforumimp.AddSubForum(req.getUser(),req.getForumId(),req.getTitle(),req.getUser().getUserName());
          if (flag == true)
          {
              this.notifyForum(req.getForumId(), "New Sub Forum was added : " + req.getTitle());
              this.GetForum(req);
          }
          else
              this.CurrentCallback.AutherizationError();
        }



        //dont need
        public void EditSubForum(Common.ClientRequest req)
        {
            
        }

        public void DeleteSubForum(Common.ClientRequest req)
        {
            Boolean flag=logicforumimp.RemoveSubForum(req.getUser(), req.getForumId(), req.getSubForumId());
            if (flag == true)
            {
                this.notifyForum(req.getForumId(),"a Sub Forum was deleted from the Forum");
                this.GetForum(req);
            }
            else
                this.CurrentCallback.AutherizationError();
           
        }

        public void GetThread(Common.ClientRequest req)
        {
            Thread thread = this.logicforumimp.getThread(req.getUser(), req.getForumId(), req.getSubForumId(),req.getThreadId());
            IClientCommunication callback = this.GetUserCallBack(req.getUser());
            if (thread != null)
                callback.ReceiveThread(thread);
            else
            {
                //if dont have the permission to do it
                // callback.AutherizationError();
            }
        }

        public void AddThread(Common.ClientRequest req)
        {
            Boolean flag = logicforumimp.AddThread(req.getUser(), req.getForumId(), req.getSubForumId(),req.getTitle(), req.getContent());
            if (flag == true)
            {
                this.CurrentCallback.ReceiveNotify("a new Thread was added");
                this.GetSubForum(req);
            }
            else
                this.CurrentCallback.AutherizationError();

        }

        public void EditThread(Common.ClientRequest req)
        {
            Boolean flag = logicforumimp.EditThread(req.getUser(), req.getForumId(), req.getSubForumId(), req.getThreadId(), req.getTitle(), req.getContent());
            if (flag == true)
                this.CurrentCallback.ReceiveNotify("the Thread was edited");
            else
                this.CurrentCallback.AutherizationError();
        }

        public void DeleteThread(Common.ClientRequest req)
        {
            Boolean flag = logicforumimp.RemoveThread(req.getUser(), req.getForumId(), req.getSubForumId(),req.getThreadId());
            if (flag == true){
                this.CurrentCallback.ReceiveNotify("the Thread was deleted");
                this.GetSubForum(req);
            }
            else
                this.CurrentCallback.AutherizationError();
        }


        //no need to implement
        public void GetPost(Common.ClientRequest req)
        {
            Post post = this.logicforumimp.getPost(req.getUser(), req.getForumId(), req.getSubForumId(), req.getThreadId(),req.getPostId());
            IClientCommunication callback = this.GetUserCallBack(req.getUser());
            if (post != null)
                return;//  callback.re(post);
            else
            {
                //if dont have the permission to do it
                // callback.AutherizationError();
            }
        }

        public void AddPost(Common.ClientRequest req)
        {
            Boolean flag = logicforumimp.AddPost(req.getUser(),req.getForumId(),req.getSubForumId(),req.getThreadId(), req.getTitle(),req.getContent());
            if (flag == true)
            {
                this.CurrentCallback.ReceiveNotify("the Post was added");
                this.GetThread(req);
            }
            else
                this.CurrentCallback.AutherizationError();
        }

        public void EditPost(Common.ClientRequest req)
        {
            Boolean flag = logicforumimp.EditPost(req.getUser(), req.getForumId(), req.getSubForumId(), req.getThreadId(),req.getPostId(), req.getTitle(), req.getContent());
            if (flag == true)
                this.CurrentCallback.ReceiveNotify("the Post was edited");
            else
                this.CurrentCallback.AutherizationError();
           
        }

        public void DeletePost(Common.ClientRequest req)
        {
            Boolean flag = logicforumimp.RemovePost(req.getUser(), req.getForumId(), req.getSubForumId(),req.getThreadId(),req.getPostId());
            if (flag == true)
            {
                this.CurrentCallback.ReceiveNotify("the Post was edited");
                this.GetThread(req);
            }
            else
                this.CurrentCallback.AutherizationError();
        }

        public void AddModerator(Common.DataBaseNew.User me, string moderatorname, string subforum,int forumid)
        {
            int subforumid=logicforumimp.getSubForumID(forumid,subforum);
            
            Boolean flag= logicforumimp.AddNewModeratorToSubForum(me,forumid,subforumid,moderatorname);
            if (flag == true)
                this.notifyForum(forumid, moderatorname + " was appointed to moderate " + subforum);
            else
                this.CurrentCallback.AutherizationError();

        }

        public void DeleteModerator(Common.DataBaseNew.User me, string moderatorname, string subforum,int forumid)
        {
            int subforumid = logicforumimp.getSubForumID(forumid, subforum);
            Boolean flag = logicforumimp.RemoveModerator(me, forumid, subforumid, moderatorname);
            if (flag == true)
                this.notifyForum(forumid, moderatorname + " was removed from moderating " + subforum);
            else
                this.CurrentCallback.AutherizationError();
        }

        public void ExchangeModerator(Common.DataBaseNew.User me,string oldMod, string newMod, string subforum,int forumid)
        {
            int subforumid = logicforumimp.getSubForumID(forumid, subforum);
            Boolean flag = logicforumimp.ChangeTheSubForumModerator(me, forumid, subforumid, oldMod, newMod);
            if (flag == true)
                this.notifyForum(forumid, newMod + " has taken moderating insted of " + oldMod + " in subforum "+ subforum);
            else
                this.CurrentCallback.AutherizationError();
        }

        //dont need AddForum(Common.DataBaseNew.User me, string name, string forum)
        

        //dont need
        public void DeleteManager(Common.DataBaseNew.User me, string name, string forum)
        {
            
        }


        public void GetForumStatistics(Common.DataBaseNew.User me, int forumID)
        {
          string str="";
          str =str+ logicforumimp.getAllStatistic(me, forumID);
            
          IClientCommunication callback = this.GetUserCallBack(me);
          callback.ReceiveForumStatistics(str);
          
           
        }

        public void GetSystemStatistics(string admin, string adminPassword)
        {//the director doing it
            User director=logicforumimp.getdirector(admin,adminPassword);
            if (director==null)
                return;
            IClientCommunication callback = this.GetUserCallBack(director);
            string str="the number of common users are : "+ logicforumimp.getNumberOfCommonUsers(director);
            str=str+"\r\n the number of forums:" +logicforumimp.getNumberOfForum(director)+" \r\n";
            //change Ilya
            //callback.ReceiveSystemStatistics(logicforumimp.getUserLists(),str);
            User user = logicforumimp.getdirector(admin, adminPassword);
            if (callback == null)
            {
                IClientCommunication ic = this.CurrentCallback;
                users.Add(user, ic);
                ic.ReceiveSystemStatistics(logicforumimp.getForumUsers(1).Keys.ToList(), str, user);//this is a stab!!!!!!
            }
            else
                callback.ReceiveSystemStatistics(logicforumimp.getForumUsers(1).Keys.ToList(), str, user);//this is a stab!!!!!!
            
            
        }

        public void getUserList()
        {//to implement this function
            throw new NotImplementedException();
        }





        public void getSystemUserList()
        {
            throw new NotImplementedException();
        }

        public void getForumUserList(User user, int forumID)
        {
            IClientCommunication callback = this.GetUserCallBack(user);
            callback.ReceiveForumUsersList(logicforumimp.getForumUsers(forumID).Keys.ToList());
        }

        public bool Subscribe()
        {
            throw new NotImplementedException();
        }


        public void AdminExit(User user)
        {
            users.Remove(user);
        }

        private IClientCommunication GetUserCallBack(User user)
        {
            if (users.ContainsValue(CurrentCallback))
            {
                foreach (User u in users.Keys)
                {
                    if (user.getName().Equals(u.getName()))
                    {
                        IClientCommunication userCallBack = users[u];
                        return userCallBack;
                        break;
                    }
                }
            }
            return null;
        }

        private void notifyForum(int forumId, string message)
        {
            SortedDictionary<string,User> forumUsers = this.logicforumimp.getForumUsers(forumId);
            foreach (User user in users.Keys)
                {
                    if(forumUsers.ContainsValue(user))
                    {
                        
                        IClientCommunication callback = this.GetUserCallBack(user);
                        callback.ReceiveNotify(message);
                    }
                }
        }
        
    }
}
